//第七章 函数表达式
console.log("--------第七章 函数表达式-------")

function test(){

}
console.log(test.name); //得到函数的名称 只在Firefox、Safari、Chrome 和Opera 有效

//匿名函数
var myFn = function (){
    console.log("----匿名函数输出-----")
}; //函数的定义是匿名的 但是把它赋值给 myFn 变量后可以认为有名字了
console.log(myFn.name);

//函数表达式
var factorial = (function f(n) {
    if(n<=1)
    {
        return 1;
    }else
    {
        return n*f(n-1);
    }
});

var factVal = factorial(5);
console.log('factVal=',factVal);

//闭包
function out(n) {
    var num = n+1;
    return function () {
        num++;
        return num;
    }
}

var f = out(5);
var v = f();
v = f();
console.log('--闭包--',v);

//通过闭包实现类型迭代器的next方法
function decorator(arr) {
    return function () {
        if(arr.length>0){
            return arr.shift();
        }else{
            throw new RangeError("已经超出数组范围");
        }
    }
}

var ary = [1,2,3,4];
var next = decorator(ary); //闭包函数会返回包含它的函数的作用域链，一个函数如果返回多个闭包函数，则会共享作用域
/*
console.log('next=',next());
console.log('next=',next());
console.log('next=',next());
console.log('next=',next());        
console.log('next=',next());        
*/

//理解闭包共享作用域
function createFn(){
    var result = [];
    for (var i = 0; i < 5; i++) { //es6 let 关键字可以创建块级作用域变量
        result[i] = function () {
            return i;
        };
        
    }
    console.log('createFn:',i)
    return result;
}
var rets= createFn()
var idex = 0
while(idex<rets.length){
    console.log(rets[idex]()); //每次都是返回5 因为共享 createFn 函数的作用域链,createFn 执行到最后 i的值是5
    idex++;
}

//this 关键字在闭包中的使用
var myName = "the window";
var myObj = {
    myName:"the Object",
    myFn:function () {
        return function () {
            return this.myName;
        }
    }
};

console.log(myObj.myFn()()); //这里输出 the window 因为返回的闭包函数是全局对象的属性 相当于在全局作用域下执行

//通过函数表达式实现块级变量(私有作用域
(function () {
    myPrivateName = "myPrivateName33";
    (function (){
        for(var i = 0;i <5;i++)
        {

        }
    })();    
    //alert(i);// 这里会出错,i变量只能在函数表达式作用域内有效
})();
console.log(myPrivateName);//这里有效 因为变量没有通过var关键字定义，会是全局变量

//实现静态私有变量
(function (){
    var myProperty = 100;
    MyObject = function () { //构造函数，没有用var关键字定义所以可以在全局中访问
        
    };
    MyObject.prototype.getMyProperty = function () {
        return myProperty; //所有对象访问到的都是一样的值
    }
    MyObject.prototype.setMyProperty = function (v){
        myProperty = v;
    }

})(); //通过函数表达式创建的类(暂且这样说),函数表达内的变量是块级变量，所有实例共享

var myObj1 = new MyObject();
console.log('myObj1.getMyProperty=',myObj1.getMyProperty());

var myObj2 = new MyObject();
myObj2.setMyProperty(120); //该出修改会影响myObj1的值

console.log('myObj1.getMyProperty=',myObj1.getMyProperty());
console.log('myObj2.getMyProperty=',myObj2.getMyProperty());

//模块模式 创建单例
var singleton = function (){
    var privateNum = 100;
    function privateFn(){
        privateNum++;
        return privateNum;
    }
    return {
        publicNum:200,
        publicFn:function (){
            return privateFn;
        }
    };

}();

var f = singleton.publicFn();
console.log('singleton f:',f());
console.log('singleton f:',f());